<!DOCTYPE html>
<html lang="zh-CN">

<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>表单设计器（拖拽版 - 修复完整版）</title>
  <style>
    body {
      font-family: Arial, sans-serif;
      margin: 0;
      padding: 0;
      background: #f5f5f5;
    }

    .container {
      display: flex;
      height: calc(100vh - 40px);
    }

    .sidebar {
      width: 200px;
      background: #fff;
      border-right: 1px solid #ddd;
      padding: 10px;
      box-shadow: 2px 0 5px rgba(0, 0, 0, 0.1);
      overflow-y: auto;
    }

    .sidebar h3 {
      margin-top: 0;
      font-size: 14px;
    }

    .form-field {
      padding: 8px;
      margin: 8px 0;
      background: #f0f0f0;
      border: 1px solid #ccc;
      border-radius: 4px;
      cursor: grab;
      text-align: center;
      font-size: 12px;
    }

    .form-field:hover {
      background: #e0e0e0;
    }

    .canvas {
      flex: 1;
      background: #fff;
      padding: 20px;
      overflow-y: auto;
      position: relative;
    }

    .canvas h2 {
      margin-top: 0;
      font-size: 16px;
      border-bottom: 1px solid #eee;
      padding-bottom: 5px;
    }

    .section {
      margin-bottom: 20px;
      padding: 10px;
      border: 1px solid #eee;
      border-radius: 5px;
      background: #fafafa;
    }

    .section h3 {
      margin-top: 0;
      font-size: 14px;
    }

    #fields-container,
    #button-container,
    #onload-container,
    #onsave-container {
      min-height: 50px;
      border: 2px dashed #ddd;
      padding: 10px;
      margin-top: 10px;
      transition: background-color 0.3s;
    }

    #fields-container.drag-over,
    #button-container.drag-over,
    #onload-container.drag-over,
    #onsave-container.drag-over {
      background-color: #f0f8ff;
      border-color: #007bff;
    }

    .dropped-field,
    .dropped-action {
      margin: 8px 0;
      padding: 8px;
      border: 1px dashed #aaa;
      border-radius: 4px;
      background: #fff;
      cursor: pointer;
      position: relative;
    }

    .dropped-field:hover,
    .dropped-action:hover {
      background: #f0f0f0;
    }

    .config-panel {
      width: 300px;
      background: #fff;
      border-left: 1px solid #ddd;
      padding: 20px;
      overflow-y: auto;
    }

    .tabs {
      display: flex;
      border-bottom: 1px solid #ddd;
      margin-bottom: 10px;
    }

    .tab {
      padding: 8px 16px;
      cursor: pointer;
      border-bottom: 2px solid transparent;
      font-size: 14px;
    }

    .tab.active {
      border-bottom: 2px solid #007bff;
      font-weight: bold;
    }

    .tab-content {
      display: none;
    }

    .tab-content.active {
      display: block;
    }

    .json-preview {
      font-family: monospace;
      white-space: pre-wrap;
      background: #f5f5f5;
      padding: 10px;
      border-radius: 4px;
      max-height: 1200px;
      height: calc(100% - 90px);
      overflow-y: auto;
      font-size: 12px;
    }

    .export-btn {
      position: fixed;
      bottom: 20px;
      right: 20px;
      padding: 10px 20px;
      background: #007bff;
      color: white;
      border: none;
      border-radius: 4px;
      cursor: pointer;
      font-size: 14px;
    }

    .export-btn:hover {
      background: #0056b3;
    }

    .form-group {
      margin-bottom: 10px;
    }

    .form-group label {
      display: block;
      margin-bottom: 4px;
      font-size: 12px;
      font-weight: bold;
    }

    .form-group input,
    .form-group select,
    .form-group textarea {
      width: 100%;
      padding: 5px;
      border: 1px solid #ddd;
      border-radius: 3px;
      font-size: 12px;
      box-sizing: border-box;
    }

    .form-group textarea {
      min-height: 60px;
    }

    .btn {
      padding: 5px 10px;
      background: #007bff;
      color: white;
      border: none;
      border-radius: 3px;
      cursor: pointer;
      font-size: 12px;
    }

    .btn:hover {
      background: #0056b3;
    }

    .btn {
      padding: 5px 10px;
      background: #007bff;
      color: white;
      border: none;
      border-radius: 3px;
      cursor: pointer;
      font-size: 12px;
    }

    .btn:hover {
      background: #0056b3;
    }

    /* 定义块样式 */
    .definition-header {
      background-color: #f8f9fa;
      border: 1px solid #ddd;
      border-radius: 5px;
      margin-bottom: 15px;
      overflow: hidden;
    }

    .definition-header-title {
      display: flex;
      justify-content: space-between;
      align-items: center;
      padding: 10px;
      border-bottom: 1px solid #ddd;
      background-color: #f1f3f4;
    }

    .definition-header-title h3 {
      margin: 0;
      font-size: 14px;
      color: #333;
    }

    .definition-header-title2 {
      display: flex;
      justify-content: space-between;
      align-items: center;
      border-bottom: 1px solid #ddd;
    }

    .definition-header-title2 h3 {
      margin: 0;
      font-size: 16px;
      color: #333;
    }

    .definition-content {
      display: flex;
      flex-wrap: wrap;
      gap: 20px;
      padding: 10px;
      transition: all 0.3s ease;
    }


    .definition-section {
      flex: 1;
      min-width: 200px;
    }

    .definition-section h3 {
      margin: 0 0 5px 0;
      font-size: 14px;
      color: #333;
    }

    .toggle-btn {
      background: none;
      border: none;
      font-size: 16px;
      cursor: pointer;
      padding: 5px;
      color: #666;
      transition: transform 0.3s ease;
    }

    .toggle-btn.collapsed {
      transform: rotate(180deg);
    }

    .input-tip {
      font-size: 11px !important;
      font-weight: normal !important;
      color: #8f6423;
    }
  </style>

  <link rel="stylesheet" href="css/collapsed.css">
  <link rel="stylesheet" href="css/block.css">
  <link rel="stylesheet" href="css/menubar.css">

  <script src="jsform/menubar.js"></script>
  <script src="jsform/modelDefine.js"></script>
  <script src="jsform/preview.js"></script>
</head>

<body>

  <!-- 顶部工具栏：新建/保存/打开 -->
  <div
    style="position:fixed;top:0;left:0;right:0;height:40px;background:#fff;border-bottom:1px solid #ddd;display:flex;align-items:center;padding:0 20px;z-index:999;box-shadow:0 2px 4px rgba(0,0,0,.05);">
    <button class="toolbar-btn" onclick="newForm()">🆕 新建</button>
    <button class="toolbar-btn" onclick="saveForm()">💾 保存</button>
    <button class="toolbar-btn" onclick="openForm()">📂 打开</button>
    <input type="file" id="fileInput" accept=".json" style="display:none;" onchange="loadFormFile(event)" />
    <button class="toolbar-btn" onclick="previewForm()" title="预览表单">👁️ 预览</button>
  </div>
  <!-- 为顶部工具栏留出空间 -->
  <div style="height:40px;"></div>

  <div class="container">
    <!-- 左侧组件栏 -->
    <div class="sidebar">
      <h3>表单组件</h3>
      <div class="form-field" draggable="true" data-type="input">输入框</div>
      <div class="form-field" draggable="true" data-type="select">下拉框</div>
      <div class="form-field" draggable="true" data-type="input-number">数值输入</div>
      <div class="form-field" draggable="true" data-type="textarea">文本域</div>
      <div class="form-field" draggable="true" data-type="image-list-upload">图片列表上传</div>
      <div class="form-field" draggable="true" data-type="label">标签</div>
      <div class="form-field" draggable="true" data-type="geo-location">位置</div>

      <h3>页面按钮</h3>
      <div class="form-field" draggable="true" data-type="button-ok">确认按钮</div>
      <div class="form-field" draggable="true" data-type="button-close">关闭按钮</div>
      <div class="form-field" draggable="true" data-type="button-locate">定位按钮</div>
      <div class="form-field" draggable="true" data-type="button-cancel">取消按钮</div>

      <h3>初始化方法</h3>
      <div class="form-field" draggable="true" data-type="fetch-model-data">获取Model数据</div>
      <div class="form-field" draggable="true" data-type="field-transform">字段转换</div>
      <div class="form-field" draggable="true" data-type="map-locate">定位实体</div>
      <div class="form-field" draggable="true" data-type="fetch-select-options">获取下拉选项</div>

      <h3>保存方法</h3>
      <div class="form-field" draggable="true" data-type="field-transform">字段反转</div>
      <div class="form-field" draggable="true" data-type="save-model-data">保存Model数据</div>
      <div class="form-field" draggable="true" data-type="insert-model-data">插入Model数据</div>
      <div class="form-field" draggable="true" data-type="upload-img">上传图片</div>
      <div class="form-field" draggable="true" data-type="upload-file">上传文件</div>
    </div>

    <!-- 中间画布 -->
    <div class="canvas" id="canvas">
      <!-- 定义块区域 -->
      <div class="definition-header">
        <div class="definition-header-title">
          <h3>Model定义</h3>
          <button id="toggleDefinition" class="toggle-btn" title="折叠/展开Model定义">●</button>
        </div>
        <div class="definition-content">
          <div class="definition-section">
            <div class="form-group">
              <label>表单标题</label>
              <input type="text" id="formTitle" placeholder="输入表单标题" />
            </div>
            <div class="form-group">
              <label>数据源地址</label>
              <input type="text" id="dataSourceUrl" placeholder="输入数据源地址" />
            </div>
            <div class="form-group">
              <label>备注</label>
              <textarea id="formRemark" placeholder="输入备注信息" rows="2"></textarea>
            </div>
          </div>
          <div class="definition-section">
            <div class="form-group">
              <label>创作者</label>
              <input type="text" id="formCreator" placeholder="输入创作者名称" />
            </div>
            <div class="form-group">
              <label>数据表名称</label>
              <input type="text" id="dataTableName" placeholder="输入数据表名称" />
            </div>
            <button class="btn" onclick="saveModelDefinition()">保存Model定义</button>
          </div>
          <div class="definition-section">
            <div class="form-group">
              <label>页面宽高</label>
              <input type="number" id="pageWidth" placeholder="输入页面宽度（像素）" style="width:80px;" min="320" max="2920"
                value="800" />
              ×
              <input type="number" id="pageHeight" placeholder="输入页面高度（像素）" style="width:80px;" min="400" max="2080"
                value="600" />
            </div>
            <div class="form-group">
              <label>字段定义</label>
              <input id="modelFields" placeholder="输入字段名，逗号分隔&#10;例如：A,B,C,D" rows="2"></input>
            </div>
          </div>
        </div>
      </div>

      <div class="section">
        <div class="definition-header-title2">
          <h3>表单字段</h3>
          <button id="toggleDefinition-fields-container" class="toggle-btn" title="折叠/展开Model定义">●</button>
        </div>
        <div id="fields-container" class="definition-content"></div>
      </div>
      <div class="section">
        <div class="definition-header-title2">
          <h3>按钮组</h3>
          <button id="toggleDefinition-button-container" class="toggle-btn" title="折叠/展开Model定义">●</button>
        </div>
        <div id="button-container" class="definition-content"></div>
      </div>
      <div class="section">
        <div class="definition-header-title2">
          <h3>onLoad 生命周期</h3>
          <button id="toggleDefinition-onload-container" class="toggle-btn" title="折叠/展开Model定义">●</button>
        </div>
        <div id="onload-container" class="definition-content"></div>
      </div>
      <div class="section">
        <div class="definition-header-title2">
          <h3>onSave 生命周期</h3>
          <button id="toggleDefinition-onsave-container" class="toggle-btn" title="折叠/展开Model定义">●</button>
        </div>
        <div id="onsave-container" class="definition-content"></div>
      </div>
    </div>

    <!-- 右侧配置面板 -->
    <div class="config-panel">
      <div class="tabs">
        <div class="tab active" data-tab="field">字段配置</div>
        <div class="tab" data-tab="action">动作配置</div>
        <div class="tab" data-tab="json">JSON预览</div>
      </div>

      <div class="tab-content active" data-tab="field">
        <div id="fieldConfig">
          <p>请选择画布中的字段进行配置</p>
        </div>
      </div>

      <div class="tab-content" data-tab="action">
        <div id="actionConfig">
          <p>请选择生命周期中的动作进行配置</p>
        </div>
      </div>

      <div class="tab-content" data-tab="json">
        <div class="json-preview" id="jsonPreview">{}</div>
      </div>
    </div>
  </div>

  <!-- 导出按钮 -->
  <script type="module">
    import FieldsContainer from './js/FieldsContainer.js';
    import Field from './js/Field.js';
    import Action from './js/Action.js';
    import ActionContainer from './js/ActionContainer.js';
    import DropZones from './js/DropZones.js';
    import ToggleBlock from './js/ToggleBlock.js';
    import FormConfigManager from './js/FormConfigManager.js';

    // 将FieldsContainer添加到全局作用域，以便在内联事件处理器中使用
    window.FieldsContainer = FieldsContainer;
    window.Field = Field;
    window.Action = Action;
    window.ActionContainer = ActionContainer;
    window.DropZones = DropZones;
    window.FormConfigManager = FormConfigManager;

    DropZones.init();

    // ==== 初始化 ====
    document.addEventListener('DOMContentLoaded', () => {
      initializeDefinitionBlock();

      // 初始化标签切换
      document.querySelectorAll('.tab').forEach(tab => {
        tab.addEventListener('click', () => {
          // 移除所有标签的active类
          document.querySelectorAll('.tab').forEach(t => t.classList.remove('active'));
          document.querySelectorAll('.tab-content').forEach(c => c.classList.remove('active'));

          // 添加当前标签的active类
          tab.classList.add('active');
          const tabName = tab.getAttribute('data-tab');
          document.querySelector(`.tab-content[data-tab="${tabName}"]`).classList.add('active');

          // 如果切换到JSON预览标签，更新预览
          if (tabName === 'json') {
            updateJsonPreview();
          }
        });
      });


      // 初始化JSON预览
      updateJsonPreview();
    });

    ToggleBlock.init();

    // ==== 拖拽功能 ====
    // 1. 设置所有表单组件为可拖拽
    document.querySelectorAll('.form-field').forEach(el => {
      el.draggable = true;
      el.addEventListener('dragstart', (e) => {
        e.dataTransfer.effectAllowed = 'copy';
        e.dataTransfer.setData('text/plain', e.target.dataset.type);
        e.target.style.opacity = '0.5';
      });

      el.addEventListener('dragend', (e) => {
        e.target.style.opacity = '';
      });
    });

    // ==== 更新函数 ====
    function addFieldOption() {
      if (!selectedItem || selectedItem.type !== 'field') return;
      const field = selectedItem.data;
      if (!field.options) field.options = [];
      field.options.push({ label: '新选项', value: 'new_value' });
      renderFieldOptions(field);
    }

    // 点击选择字段的辅助函数
    function selectFieldByClick(event, key) {
      event.stopPropagation();
      const field = formConfig.formConfig.fields.find(f => f.uuid === key);
      if (field) {
        selectField(field);
        switchToTab('field');
      }
    }
    window.selectFieldByClick = selectFieldByClick;
  </script>
  <script>
    let formConfig = {
      metadata: {
        title: "动态表单",
        version: "1.0.0",
        name: "",
        fields: []
      },
      formConfig: {
        fields: [],
        buttons: [],
        onLoad: [],
        onSave: []
      }
    };
    let selectedItem = null; // { type: 'field'|'action', data: object }
    // ==== 全局变量 ====
    const canvas = document.getElementById('canvas');

    const fieldConfigPanel = document.getElementById('fieldConfig');
    const actionConfigPanel = document.getElementById('actionConfig');
    const jsonPreview = document.getElementById('jsonPreview');

    let fieldCounter = 0;
    let actionCounter = 0;
    // ==== JSON预览与导出 ====
    function updateJsonPreview() {
      jsonPreview.textContent = JSON.stringify(formConfig, null, 2);
    }

    // ==== 应用配置函数 ====
    function applyFieldConfig() {
      if (!selectedItem || selectedItem.type !== 'field') return;

      const field = selectedItem.data;
      const oldKey = field.key; // 保存旧的key值

      field.collectSetting();

      // 更新图片上传配置（如果有）
      if (field.type === 'image-list-upload') {
        const limitInput = document.getElementById('fieldLimit');
        const fileTypeInput = document.getElementById('fieldFileType');
        const fileSizeInput = document.getElementById('fieldFileSize');

        if (limitInput) {
          field.props.limit = parseInt(limitInput.value);
        }
        if (fileTypeInput) {
          field.props.fileType = fileTypeInput.value.split(',').map(t => t.trim());
        }
        if (fileSizeInput) {
          field.props.fileSize = parseInt(fileSizeInput.value);
        }
      }

      // 更新动态标签配置（如果有）
      if (field.type === 'label') {
        const dependsOnInput = document.getElementById('fieldDependsOn');
        if (dependsOnInput) {
          field.props.dependsOn = dependsOnInput.value;
        }

        // 更新选项映射
        const optionInputs = document.querySelectorAll('#labelOptionsContainer input');
        field.options = {};
        for (let i = 0; i < optionInputs.length; i += 2) {
          if (i + 1 < optionInputs.length) {
            field.options[optionInputs[i].value] = optionInputs[i + 1].value;
          }
        }
      }
      field.collectOptionSettings();

      FieldsContainer.updateField(field, oldKey, DropZones.fieldsContainer);

      // 更新JSON预览
      updateJsonPreview();
    }

    // 删除字段
    function removeField(key) {
      const index = formConfig.formConfig.fields.findIndex(f => f.uuid === key);
      if (index !== -1) {
        formConfig.formConfig.fields.splice(index, 1);
        // 重新渲染字段容器
        DropZones.fieldsContainer.innerHTML = '';
        formConfig.formConfig.fields.forEach(field => {
          FieldsContainer.renderField(field, DropZones.fieldsContainer);
        });
        // 如果删除的是当前选中的字段，清空配置面板
        if (selectedItem && selectedItem.type === 'field' && selectedItem.data.key === key) {
          selectedItem = null;
          fieldConfigPanel.innerHTML = '<p>请选择画布中的字段进行配置</p>';
        }
        updateJsonPreview();
      }
    }

    function applyActionConfig() {
      if (!selectedItem || selectedItem.type !== 'action') return;

      const action = selectedItem.data;

      // 更新API地址（如果有）
      const apiInput = document.getElementById('actionApi');
      if (apiInput) {
        action.api = apiInput.value;
      }


      // 更新地图动作（如果有）
      const mapActionInput = document.getElementById('actionMapAction');
      if (mapActionInput) {
        action.action = mapActionInput.value;
      }

      // 更新参数（如果有）
      const paramsInput = document.getElementById('actionParams');
      if (paramsInput) {
        try {
          action.params = JSON.parse(paramsInput.value);
        } catch (e) {
          alert('参数JSON格式错误，请检查后重试');
          return;
        }
      }
      action.collectActionConfig();

      ActionContainer.updateAction(action);

      // 更新JSON预览
      updateJsonPreview();

    }


    // 点击选择动作的辅助函数
    function selectActionByClick(event, id) {
      event.stopPropagation();
      let action = null;
      // 先在onLoad中查找
      action = formConfig.formConfig.onLoad.find(a => a.uuid === id);
      // 如果没找到，在onSave中查找
      if (!action) {
        action = formConfig.formConfig.onSave.find(a => a.uuid === id);
      }
      if (action) {
        selectAction(action);
        switchToTab('action');
      }
    }

    function selectAction(action) {
      selectedItem = { type: 'action', data: action };
      action.showActionConfig(actionConfigPanel);
    }

    // ==== 辅助函数 ====
    function switchToTab(tabName) {
      // 移除所有标签的active类
      document.querySelectorAll('.tab').forEach(t => t.classList.remove('active'));
      document.querySelectorAll('.tab-content').forEach(c => c.classList.remove('active'));

      // 添加指定标签的active类
      document.querySelector(`.tab[data-tab="${tabName}"]`).classList.add('active');
      document.querySelector(`.tab-content[data-tab="${tabName}"]`).classList.add('active');

      // 如果切换到JSON预览标签，更新预览
      if (tabName === 'json') {
        updateJsonPreview();
      }
    }


    // ==== 处理放置 ====
    function handleFieldDrop(type) {
      fieldCounter++;
      // 获取Model字段列表
      const modelFields = formConfig.metadata.fields || [];
      // 如果有Model字段，使用第一个字段作为默认key，否则使用原来的方式
      const key = modelFields.length > 0 ? modelFields[0] : `${type}_${fieldCounter}`;
      const field = new Field({
        key: key,
        type: type,
        label: `${type}字段${fieldCounter}`,
      });

      formConfig.formConfig.fields.push(field);
      FieldsContainer.renderField(field, DropZones.fieldsContainer);

      // 自动切换到字段配置标签
      switchToTab('field');
      // 自动选中新添加的字段
      selectField(field);
    }

    function handleActionDrop(type, dropType) {
      actionCounter++;
      const action = new Action({
        id: `action_${actionCounter}`,
        type: type
      })

      formConfig.formConfig[dropType].push(action);
      ActionContainer.renderAction(action, DropZones.getContainer(dropType));

      // 自动切换到动作配置标签
      switchToTab('action');
      // 自动选中新添加的动作
      selectAction(action);
    }

    // ==== 选择配置 ====
    function selectField(field) {
      selectedItem = { type: 'field', data: field };
      showFieldConfig(field);
    }

    function showFieldConfig(field) {
      // 获取Model字段列表
      const modelFields = formConfig.metadata.fields || [];
      field.showFieldConfig(formConfig, fieldConfigPanel);
    }

  </script>
</body>

</html>